package com.prj.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.prj.dto.AllocRoleDTO;
import com.prj.dto.LoginDTO;
import com.prj.dto.RoleDTO;
import com.prj.dto.UserDTO;
import com.prj.dto.UserQueryDTO;
import com.prj.entity.Menu;
import com.prj.entity.MenuRoleRelation;
import com.prj.entity.Role;
import com.prj.entity.User;
import com.prj.entity.UserRoleRelation;
import com.prj.exception.TokenExpiredException;
import com.prj.service.MenuRoleRelationService;
import com.prj.service.MenuService;
import com.prj.service.RoleService;
import com.prj.service.UserRoleRelationService;
import com.prj.service.UserService;
import com.prj.utils.JwtUtils;
import com.prj.vo.PageVO;
import com.prj.vo.Result;
import com.prj.vo.RoleVO;
import com.prj.vo.UserVO;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "用户管理")
@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private MenuService menuService;

    @Autowired
    private UserRoleRelationService userRoleRelationService;

    @Autowired
    private MenuRoleRelationService menuRoleRelationService;

    @Operation(summary = "登录")
    @PostMapping("login")
    public Result<String> login(@RequestBody LoginDTO loginDTO) {
        String username = loginDTO.getUsername();
        String password = loginDTO.getPassword();
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username).eq(User::getPassword, password));
        if (user != null) {
            Integer id = user.getId();
            String token = JwtUtils.generateToken(id);
            return Result.success(token);
        } else {
            return Result.error("用户名或密码错误");
        }
    }

    @Operation(summary = "获取用户信息")
    @GetMapping("info")
    public Result<UserVO> userInfo(@RequestHeader("token") String token) {
        String userId =  JwtUtils.extractUserId(token);
        Boolean validate = JwtUtils.validateToken(token, userId);
        if (validate) {
            User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getId, userId));
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            fillUserVO(userVO);
            return Result.success(userVO);
        } else {
            throw new TokenExpiredException("用户token过期请重新登录");
        }
    }

    private void fillUserVO(UserVO userVO) {
        // 设置 token buttons routes
        Integer userId = userVO.getId();
        userVO.setToken(userId.toString());
        List<UserRoleRelation> userRoleRelations = userRoleRelationService.list(new LambdaQueryWrapper<UserRoleRelation>().eq(UserRoleRelation::getUserId, userId));
        List<Integer> roleIds = userRoleRelations.stream().map(UserRoleRelation::getRoleId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(roleIds)) {
            List<MenuRoleRelation> menuRoleRelations = menuRoleRelationService.list(new LambdaQueryWrapper<MenuRoleRelation>().in(MenuRoleRelation::getRoleId, roleIds));
            List<Integer> menuIds = menuRoleRelations.stream().map(MenuRoleRelation::getMenuId).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(menuIds)) {
                List<Menu> menuList = menuService.list(new LambdaQueryWrapper<Menu>().in(Menu::getId, menuIds));
                List<String> routes = menuList.stream().filter(item -> item.getLevel().equals(1) || item.getLevel().equals(2)).map(Menu::getAcl).collect(Collectors.toList());
                userVO.setRoutes(routes);
                List<String> buttons = menuList.stream().filter(item -> item.getLevel().equals(3)).map(Menu::getAcl).collect(Collectors.toList());
                userVO.setButtons(buttons);
            }
        }
    }

    @Operation(summary = "分页查询用户")
    @PostMapping("page")
    public Result<PageVO<UserVO>> page(@RequestBody UserQueryDTO userQueryDTO) {
        String nickname = userQueryDTO.getNickname();
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<User>()
                .like(StringUtils.isNotBlank(nickname), User::getNickname, nickname).orderByDesc(User::getId);
        Page<User> userPage = userService.page(new Page<>(userQueryDTO.getCurrentPage(), userQueryDTO.getPageSize()), userLambdaQueryWrapper);
        long total = userPage.getTotal();
        List<User> records = userPage.getRecords();
        List<UserVO> userVOS = BeanUtil.copyToList(records, UserVO.class);
        for (UserVO userVO : userVOS) {
            Integer userId = userVO.getId();
            userVO.setRoles(loadRoleNameList(userId));
        }
        return Result.success(new PageVO<>(total, userVOS));
    }

    @Operation(summary = "根据id获取用户信息")
    @GetMapping("getById/{id}")
    public Result<UserVO> getById(@Parameter(description = "用户id")
                                  @PathVariable Integer id) {
        User user = userService.getById(id);
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        userVO.setRoles(loadRoleNameList(id));
        fillUserVO(userVO);
        return Result.success(userVO);
    }

    @Operation(summary = "新增/修改用户信息")
    @PostMapping("createOrEdit")
    public Result<Boolean> createOrEdit(@RequestBody UserDTO userDTO) {
        User user = BeanUtil.copyProperties(userDTO, User.class);
        return Result.success(userService.saveOrUpdate(user));
    }

    @Operation(summary = "删除用户信息")
    @DeleteMapping("remove/{id}")
    public Result<Boolean> remove(@Parameter(description = "用户id")
                                  @PathVariable Integer id) {
        userService.removeById(id);
        return Result.success(true);
    }

    @Operation(summary = "批量删除用户信息")
    @DeleteMapping("batchRemove")
    public Result<Boolean> remove(@Parameter(description = "用户id") @RequestBody List<Integer> idList) {
        userService.removeByIds(idList);
        return Result.success(true);
    }

    @Operation(summary = "给用户分配角色")
    @Transactional
    @PostMapping("allocRole")
    public Result<Boolean> allocRole(@RequestBody AllocRoleDTO allocRoleDTO) {
        Integer id = allocRoleDTO.getId();
        List<RoleDTO> roleDTOList = allocRoleDTO.getRoles();
        List<UserRoleRelation> userRoleRelations = new ArrayList<>();
        for (RoleDTO roleDTO : roleDTOList) {
            UserRoleRelation userRoleRelation = new UserRoleRelation();
            userRoleRelation.setUserId(id);
            userRoleRelation.setRoleId(roleDTO.getId());
            userRoleRelations.add(userRoleRelation);
        }
        userRoleRelationService.remove(new LambdaQueryWrapper<UserRoleRelation>().eq(UserRoleRelation::getUserId, id));
        userRoleRelationService.saveBatch(userRoleRelations);
        return Result.success(true);
    }

    private List<RoleVO> loadRoleNameList(Integer userId) {
        List<RoleVO> roles = new ArrayList<>();
        List<UserRoleRelation> userRoleRelations = userRoleRelationService.list(new LambdaQueryWrapper<UserRoleRelation>()
                .eq(UserRoleRelation::getUserId, userId));
        if (CollectionUtil.isNotEmpty(userRoleRelations)) {
            List<Integer> roleIdList = userRoleRelations.stream().map(UserRoleRelation::getRoleId).collect(Collectors.toList());
            List<Role> roleList = roleService.list(new LambdaQueryWrapper<Role>().in(Role::getId, roleIdList));
            roles = BeanUtil.copyToList(roleList, RoleVO.class);
        }
        return roles;
    }
}

